
`include "common_header.verilog"

//  *************************************************************************
//  File : top_xlgmac_64
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2014 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Daniel Koehler, Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : 40G MAC toplevel with host interface and FIFOs
//  Version     : $Id: top_xlgmac_64.v,v 1.28 2017/01/03 00:11:01 dk Exp $
//  *************************************************************************

module top_xlgmac_64 (

   reset_reg_clk,
   reset_rxclk,
   reset_txclk,
   reset_ff_rx_clk,
   reset_ff_tx_clk,
   reg_clk,
   reg_rden,
   reg_wren,
   reg_addr,
   reg_data_in,
   reg_data_out,
   reg_busy,
   reg_ts_avail,
   reg_lowp,
   reg_lowp_ena,
   lpi_txhold,
   mdc,
   mdio_in,
   mdio_out,
   mdio_oen,
   loc_fault,
   rem_fault,
   li_fault,
   tx_loc_fault,
   tx_rem_fault,
   tx_li_fault,
   phy_txena,
   phy_los,
   loop_ena,
   pfc_mode,
   pause_on,
   xoff_gen,
   tx_sfd_o,
   frc_in_tx,
   rx_sfd_o,
   frc_in_rx,
   xgmii_rx_sop_shift,
   xgmii_tx_sop_shift,
   tx_clk,
   rx_clk,
   xlgmii_txclk_ena,
   xlgmii_rxclk_ena,
   xlgmii_rxc,
   xlgmii_rxd,
   xlgmii_rxt0_next,
   xlgmii_txc,
   xlgmii_txd,
   ff_tx_clk,
   ff_tx_data,
   ff_tx_sop,
   ff_tx_eop,
   ff_tx_mod,
   ff_tx_err,
   ff_tx_crc,
   ff_tx_wren,
   ff_tx_rdy,
   ff_tx_septy,
`ifdef MTIP_PARITY_PROT
   ff_tx_par_odd,
   ff_tx_par_check_ena,
   ff_tx_data_par,
   ff_tx_ctrl_par,
   ff_tx_data_par_err,
   ff_tx_ctrl_par_err,
`endif
   ff_tx_id,
   ff_tx_ts_frm,
`ifdef USER_PREAMBLE_ENA
   ff_tx_preamble,
   ff_rx_preamble,
`endif
   ff_rx_clk,
   ff_rx_data,
   ff_rx_sop,
   ff_rx_eop,
   ff_rx_mod,
   ff_rx_err,
   ff_rx_err_stat,
`ifdef MTIP_PARITY_PROT
   ff_rx_par_odd,
   ff_rx_data_par,
   ff_rx_ctrl_par,
   ff_rx_stat_par,
`endif
   ff_rx_rdy,
   ff_rx_dval,
   ff_rx_dsav,
   ff_rx_ts,
   ff_rx_empty,
   tx_ovr_err,
   tx_underflow,
   tx_empty,
   tx_ts_val,
   tx_ts,
   tx_ts_id,
   tx_ts_frm_out
`ifdef MTIPMAC_1SIF
   ,
   os_dff_wren,
   os_tx_rden_int_sop,
   os_tx_rden_sop_pause,
   os_tx_sw_reset,
   os_tx_flush,
   os_tx_err,
   os_enable
`endif
`ifdef MTIPM10_MAGIC_ENA
   ,
   magic_ena,
   magic_ind
`endif
`ifdef MTIPMAC_XSTAT
   ,
   rsv_stat_val,
   rsv_stat,
   tsv_stat_val,
   tsv_stat
`elsif MTIPSTAT_MEM_EXTERNAL
   ,
   rstm_raddr,
   rstm_rden,
   rstm_rdata,
   rstm_wren,
   rstm_waddr,
   rstm_wdata,
   tstm_raddr,
   tstm_rden,
   tstm_rdata,
   tstm_wren,
   tstm_waddr,
   tstm_wdata
`endif
  `ifdef FFMEM_EXTERNAL
   ,
   rxd_raddr,
   rxd_rden,
   rxd_rdata,
   rxd_recc,
   rxd_wren,
   rxd_waddr,
   rxd_wdata,
   rxs_raddr,
   rxs_rden,
   rxs_rdata,
   rxs_wren,
   rxs_waddr,
   rxs_wdata,
   rxp_raddr,
   rxp_rden,
   rxp_rdata,
   rxp_wren,
   rxp_waddr,
   rxp_wdata,

   txd_raddr,
   txd_rden,
   txd_rdata,
   txd_recc,
   txd_wren,
   txd_waddr,
   txd_wdata,
   txs_raddr,
   txs_rden,
   txs_rdata,
   txs_wren,
   txs_waddr,
   txs_wdata
   `ifdef USER_PREAMBLE_ENA
   ,
   txp_raddr,
   txp_rden,
   txp_rdata,
   txp_wren,
   txp_waddr,
   txp_wdata
   `endif
  `endif
   );

`include "mtip_40geth_pack_package.verilog"
parameter RXFF_OUT_REGISTERED = 1;  // extra output registers at application interface

localparam RX_STAT_DAT_WIDTH_64 = 25;      // do NOT change

input   reset_reg_clk;          //  Active High reset for reg_clk domain
input   reset_rxclk;            //  Active High reset for rx_clk domain
input   reset_txclk;            //  Active High reset for tx_clk domain
input   reset_ff_rx_clk;        //  Active High reset for ff_rx_clk domain
input   reset_ff_tx_clk;        //  Active High reset for ff_tx_clk domain
input   reg_clk;                //  Host Interface Clock
input   reg_rden;               //  Register Read Strobe
input   reg_wren;               //  Register Write Strobe
input   [7:0] reg_addr;         //  Register Address (32-bit words)
input   [31:0] reg_data_in;     //  Write Data for Host Bus
output  [31:0] reg_data_out;    //  Read Data to Host Bus
output  reg_busy;               //  Interface Busy
output  reg_ts_avail;           //  ts_avail status bit
output  reg_lowp;               //  Low Power Indication
input   reg_lowp_ena;           //  Low Power Generation
input   lpi_txhold;             //  Request MAC to hold transmit (not serving FIFO, transmit idle)
output  mdc;                    //  2.5MHz Interface
input   mdio_in;                //  Data Bus In
output  mdio_out;               //  Data Bus Out
output  mdio_oen;               //  Data Bus Output Enable
output  loc_fault;              //  RX receives LF sequences
output  rem_fault;              //  RX receives RF sequences
output  li_fault;               //  RX receives LinkInterruption sequences
input   tx_loc_fault;           //  Force RS TX to send LF sequences
input   tx_rem_fault;           //  Force RS TX to send RF sequences
input   tx_li_fault;            //  Force RS TX to send LinkInterruption sequences
output  phy_txena;              //  PHY Transmit Enable
input   phy_los;                //  PHY loss of signal status
output  loop_ena;               //  PHY Loopback Command
output  pfc_mode;               //  Priority flow control enabled (from config)
output  [7:0] pause_on;         //  Received Flow Control Status
input   [7:0] xoff_gen;         //  Transmit Flow Control Generate
output  tx_sfd_o;               //  SFD sent in TX
input   [TS_WIDTH-1:0] frc_in_tx;       //  captured time synchronous to tx clock domain
output  rx_sfd_o;               //  SFD detected in RX
input   [TS_WIDTH-1:0] frc_in_rx;       //  captured time synchronous to rx clock domain
output  xgmii_rx_sop_shift;     //  XGMII 4-Byte Column Shift of SOP     
output  xgmii_tx_sop_shift;     //  XGMII 4-Byte Column Shift of SOP 
input   tx_clk;                 //  XLGMII Transmit clock
input   rx_clk;                 //  XLGMII Receive clock
input   xlgmii_txclk_ena;       //  XLGMII Transmit Clock Enable
input   xlgmii_rxclk_ena;       //  XLGMII Receive Clock Enable
input   [7:0] xlgmii_rxc;       //  XLGMII Receive control
input   [63:0] xlgmii_rxd;      //  XLGMII Receive data
input   xlgmii_rxt0_next;       //  XLGMII Terminate on lane 0 in next word
output  [7:0] xlgmii_txc;       //  XLGMII transmit control
output  [63:0] xlgmii_txd;      //  XLGMII transmit data
input   ff_tx_clk;              //  Transmit Local Clock
input   [63:0] ff_tx_data;      //  Data Out
input   ff_tx_sop;              //  Start of Packet
input   ff_tx_eop;              //  End of Packet
input   [2:0] ff_tx_mod;        //  Last Word Modulo
input   ff_tx_err;              //  Errored Packet
input   ff_tx_crc;              //  Append CRC on transmit
input   ff_tx_wren;             //  Write Enable
output  ff_tx_rdy;              //  FIFO Ready
output  ff_tx_septy;            //  Section Empty in Transmit FIFO
`ifdef MTIP_PARITY_PROT
input   ff_tx_par_odd;          //  If 1, odd parity used, otherwise even parity
input   ff_tx_par_check_ena;    //  If 0, no Tx parity check
input   [7:0] ff_tx_data_par;   //  Data Parity In
input   ff_tx_ctrl_par;         //  Control Parity In
output  ff_tx_data_par_err;     //  Data Parity Error
output  ff_tx_ctrl_par_err;     //  Control Parity Error
`endif
input   [TSID_WIDTH-1:0] ff_tx_id;         //  TX frame identifier
input   ff_tx_ts_frm;           //  mark frame for timestamp storage
`ifdef USER_PREAMBLE_ENA
input   [55:0] ff_tx_preamble;  //  Transmit preamble (0xd5555555555555)
output  [55:0] ff_rx_preamble;  //  Received preamble (0xd5555555555555)
`endif
input   ff_rx_clk;              //  Receive Local Clock
output  [63:0] ff_rx_data;      //  Data Out
output  ff_rx_sop;              //  Start of Packet
output  ff_rx_eop;              //  End of Packet
output  [2:0] ff_rx_mod;        //  Last Word Modulo
output  ff_rx_err;              //  Errored Packet indication
output  [RX_STAT_DAT_WIDTH_64-1:0] ff_rx_err_stat;  //  Errored Packet Status Word
`ifdef MTIP_PARITY_PROT
input   ff_rx_par_odd;          //  If 1, odd parity used, otherwise even parity
output  [7:0] ff_rx_data_par;   //  Data Parity Out
output  ff_rx_ctrl_par;         //  Control Parity Out
output  ff_rx_stat_par;         //  Status Parity Out
`endif
input   ff_rx_rdy;              //  PHY Application Ready
output  ff_rx_dval;             //  Data Valid Strobe
output  ff_rx_dsav;             //  Data Available
output  [TS_WIDTH-1:0] ff_rx_ts;        //  Receive Timestamp
output  ff_rx_empty;            //  FIFO has no data
output  tx_ovr_err;             //  FIFO overflow truncation occured
output  tx_underflow;           //  FIFO Underflow (tx_clk)
output  tx_empty;               //  TX FIFO empty (tx_clk)
output  tx_ts_val;              //  tx_ts_xxx valid indication (ff_tx_clk)
output  [TS_WIDTH-1:0] tx_ts;           //  Transmit timestamp (ff_tx_clk)
output  [TSID_WIDTH-1:0] tx_ts_id;         //  Frame identifier (ff_tx_clk)
output  tx_ts_frm_out;          //  Transmit Timestamp Frame (ff_tx_clk)
`ifdef MTIPMAC_1SIF
output  os_dff_wren;            //  Write Enable (with input protection)
output  os_tx_rden_int_sop;     //  Transmit reads first word from FIFO
output  os_tx_rden_sop_pause;   //  Transmit reads first word from internally generated pause frame
output  os_tx_sw_reset;         //  Software reset (ff_tx_clk domain)
output  os_tx_flush;            //  Flush egress pipeline (reg_clk domain)
output  os_tx_err;              //  Transmit frame error
output  os_enable;              //  enable 1-step datapath functions (reg_clk)
`endif
`ifdef MTIPM10_MAGIC_ENA
input   magic_ena;              //  enable magic packet detection (drop all others)
output  magic_ind;              //  magic packet detected indication
`endif
`ifdef MTIPMAC_XSTAT
output  rsv_stat_val;           //  Receive Statistic Vector Valid
output  [48:0] rsv_stat;        //  Receive Statistic Vector
output  tsv_stat_val;           //  Transmit Statistic Vector Valid
output  [38:0] tsv_stat;        //  Transmit Statistic Vector
`elsif MTIPSTAT_MEM_EXTERNAL
 output [STAT_CNT_ADDR-1:0] rstm_raddr;                         // Stats RX mem Read address (rxclk)
 output rstm_rden;                                              // Stats RX mem read enable (rxclk)
 input  [STAT_CNT_WIDTH+STAT_CNT_SATURATE-1:0] rstm_rdata;      // Stats RX mem Read data (rxclk)
 output rstm_wren;                                              // Stats RX mem write (rxclk)
 output [STAT_CNT_ADDR-1:0] rstm_waddr;                         // Stats RX mem write address (rxclk)
 output [STAT_CNT_WIDTH+STAT_CNT_SATURATE-1:0] rstm_wdata;      // Stats RX mem write data (rxclk)

 output [STAT_CNT_ADDR-1:0] tstm_raddr;                         // Stats TX mem Read address (txclk)
 output tstm_rden;                                              // Stats TX mem read enable (txclk)
 input  [STAT_CNT_WIDTH+STAT_CNT_SATURATE-1:0] tstm_rdata;      // Stats TX mem Read data (txclk)
 output tstm_wren;                                              // Stats TX mem write (txclk)
 output [STAT_CNT_ADDR-1:0] tstm_waddr;                         // Stats TX mem write address (txclk)
 output [STAT_CNT_WIDTH+STAT_CNT_SATURATE-1:0] tstm_wdata;      // Stats TX mem write data (txclk)

 wire   [STAT_CNT_ADDR-1:0] rstm_raddr;
 wire   rstm_rden; 
 wire   rstm_wren; 
 wire   [STAT_CNT_ADDR-1:0] rstm_waddr;
 wire   [STAT_CNT_WIDTH+STAT_CNT_SATURATE-1:0] rstm_wdata;

 wire   [STAT_CNT_ADDR-1:0] tstm_raddr;
 wire   tstm_rden; 
 wire   tstm_wren; 
 wire   [STAT_CNT_ADDR-1:0]   tstm_waddr;
 wire   [STAT_CNT_WIDTH+STAT_CNT_SATURATE-1:0] tstm_wdata;
`endif

`ifdef FFMEM_EXTERNAL        // External Memories

  output [ING_ADDR-1:0]         rxd_raddr;    //  RX Data FIFO read address (ff_rx_clk)
  output                        rxd_rden;     //  RX Data FIFO read enable (ff_rx_clk)
  input  [ING_WIDTH-1:0]        rxd_rdata;    //  RX Data FIFO read data (ff_rx_clk)
  input                         rxd_recc;     //  RX Data FIFO read data ecc error (ff_rx_clk)
  output                        rxd_wren;     //  RX Data FIFO write (rx_clk)
  output [ING_ADDR-1:0]         rxd_waddr;    //  RX Data FIFO write address (rx_clk)
  output [ING_WIDTH-1:0]        rxd_wdata;    //  RX Data FIFO write data (rx_clk)

  wire   [ING_ADDR-1:0]         rxd_raddr;
  wire                          rxd_rden;
  wire                          rxd_wren;
  wire   [ING_ADDR-1:0]         rxd_waddr;
  wire   [ING_WIDTH-1:0]        rxd_wdata;

  output [ING_ST_ADDR-1:0]      rxs_raddr;    //  RX Status read address (ff_rx_clk)
  output                        rxs_rden;     //  RX Status read enable (ff_rx_clk)
  input  [ING_SFF_WIDTH-1:0]    rxs_rdata;    //  RX Status read data (ff_rx_clk)
  output                        rxs_wren;     //  RX Status write (rx_clk)
  output [ING_ST_ADDR-1:0]      rxs_waddr;    //  RX Status write address (rx_clk)
  output [ING_SFF_WIDTH-1:0]    rxs_wdata;    //  RX Status write data (rx_clk)

  wire   [ING_ST_ADDR-1:0]      rxs_raddr;
  wire                          rxs_rden; 
  wire                          rxs_wren; 
  wire   [ING_ST_ADDR-1:0]      rxs_waddr;
  wire   [ING_SFF_WIDTH-1:0]    rxs_wdata;

  output [ING_ST_ADDR-1:0]      rxp_raddr;    //  RX Ts/Prb read address (ff_rx_clk)
  output                        rxp_rden;     //  RX Ts/Prb read enable (ff_rx_clk)
  input  [ING_SOP_WIDTH-1:0]    rxp_rdata;    //  RX Ts/Prb read data (ff_rx_clk)
  output                        rxp_wren;     //  RX Ts/Prb write (rx_clk)
  output [ING_ST_ADDR-1:0]      rxp_waddr;    //  RX Ts/Prb write address (rx_clk)
  output [ING_SOP_WIDTH-1:0]    rxp_wdata;    //  RX Ts/Prb write data (rx_clk)

  wire   [ING_ST_ADDR-1:0]      rxp_raddr;
  wire                          rxp_rden; 
  wire                          rxp_wren; 
  wire   [ING_ST_ADDR-1:0]      rxp_waddr;
  wire   [ING_SOP_WIDTH-1:0]    rxp_wdata;


  output [EG_ADDR-1:0]  txd_raddr;       // TX Read address (tx_clk)
  output                txd_rden;        // TX read enable (tx_clk)
  input  [EG_WIDTH+2-1:0] txd_rdata;     // TX Read data (tx_clk)
  input                 txd_recc;        // TX Read data ecc error (tx_clk)
  output                txd_wren;        // TX write (ff_tx_clk)
  output [EG_ADDR-1:0]  txd_waddr;       // TX write addres (ff_tx_clk)
  output [EG_WIDTH+2-1:0] txd_wdata;     // TX write data (ff_tx_clk)

  wire  [EG_ADDR-1:0]   txd_raddr;
  wire                  txd_rden;
  wire                  txd_wren;
  wire  [EG_ADDR-1:0]   txd_waddr;
  wire  [EG_WIDTH+2-1:0]  txd_wdata;

  output [EG_ST_ADDR-1:0]   txs_raddr;  // TX Status Read address (tx_clk)
  output                    txs_rden;   // TX Status read enable (tx_clk)
  input  [EG_SFF_WIDTH-1:0] txs_rdata;  // TX Status Read data (tx_clk)
  output                    txs_wren;   // TX Status write (ff_tx_clk)
  output [EG_ST_ADDR-1:0]   txs_waddr;  // TX Status write addres (ff_tx_clk)
  output [EG_SFF_WIDTH-1:0] txs_wdata;  // TX Status write data (ff_tx_clk)

  wire  [EG_ST_ADDR-1:0]    txs_raddr;
  wire                      txs_rden;
  wire                      txs_wren;
  wire  [EG_ST_ADDR-1:0]    txs_waddr;
  wire  [EG_SFF_WIDTH-1:0]  txs_wdata;

  `ifdef USER_PREAMBLE_ENA
  output [EG_ST_ADDR-1:0]   txp_raddr;  // TX preamble read address (tx_clk)
  output                    txp_rden;   // TX preamble read enable (tx_clk)
  input  [55:0]             txp_rdata;  // TX preamble read data (tx_clk)
  output                    txp_wren;   // TX preamble write (ff_tx_clk)
  output [EG_ST_ADDR-1:0]   txp_waddr;  // TX preamble write addres (ff_tx_clk)
  output [55:0]             txp_wdata;  // TX preamble write data (ff_tx_clk)

  wire  [EG_ST_ADDR-1:0]    txp_raddr;
  wire                      txp_rden;
  wire                      txp_wren;
  wire  [EG_ST_ADDR-1:0]    txp_waddr;
  wire  [55:0]              txp_wdata;
  `endif

`endif

wire    [31:0] reg_data_out;
wire    reg_busy;
wire    reg_ts_avail;
wire    reg_lowp;
wire    mdc;
wire    mdio_out;
wire    mdio_oen;
wire    loc_fault;
wire    rem_fault;
wire    li_fault;
wire    phy_txena;
wire    loop_ena;
wire    pfc_mode;
wire    [7:0] pause_on;
wire    tx_sfd_o;
wire    rx_sfd_o;
wire    xgmii_rx_sop_shift;
wire    xgmii_tx_sop_shift;
wire    [7:0] xlgmii_txc;
wire    [63:0] xlgmii_txd;
wire    ff_tx_rdy;
wire    ff_tx_septy;
`ifdef MTIP_PARITY_PROT
wire    ff_tx_data_par_err;
wire    ff_tx_ctrl_par_err;
`endif
`ifdef USER_PREAMBLE_ENA
wire    [55:0] ff_rx_preamble;
`endif
wire    [63:0] ff_rx_data;
wire    ff_rx_sop;
wire    ff_rx_eop;
wire    [2:0] ff_rx_mod;
wire    ff_rx_err;
wire    [RX_STAT_DAT_WIDTH_64-1:0] ff_rx_err_stat;
`ifdef MTIP_PARITY_PROT
wire    [7:0] ff_rx_data_par;
wire    ff_rx_ctrl_par;
wire    ff_rx_stat_par;
`endif
wire    ff_rx_dval;
wire    ff_rx_dsav;
wire    [TS_WIDTH-1:0] ff_rx_ts;
wire    ff_rx_empty;
wire    tx_ovr_err;
wire    tx_underflow;
wire    tx_empty;
wire    tx_ts_val;
wire    [TS_WIDTH-1:0] tx_ts;
wire    [TSID_WIDTH-1:0] tx_ts_id;
wire    tx_ts_frm_out;
`ifdef MTIPMAC_1SIF
wire    os_dff_wren;
wire    os_tx_rden_int_sop;
wire    os_tx_rden_sop_pause;
wire    os_tx_sw_reset;
wire    os_tx_flush;
wire    os_tx_err;
wire    os_enable;
`endif
`ifdef MTIPM10_MAGIC_ENA
wire    magic_ind;
`endif
`ifdef MTIPMAC_XSTAT
wire    rsv_stat_val;
wire    [48:0] rsv_stat;
wire    tsv_stat_val;
wire    [38:0] tsv_stat;
`endif

wire    rx_septy;                               //  rx_section_empty reached (if 0, ff_rx_clk)
wire    rx_stat_wren;                           //  Receive Status FIFO Write Enable (identical to rx_eop_int)
wire    [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data;                    //  Receive Status data
wire    [2:0] rx_mod_int;                       //  Last word modulo
wire    [63:0] rx_data_int;                     //  Receive Data to FIFO
wire    rx_sop_int;                             //  Receive Start of Packet
wire    rx_eop_int;                             //  Receive End of Packet
wire    rx_wren_int;                            //  Receive Data  FIFO Write Enable
wire    rx_a_full;                              //  Receive Data FIFO Almost Full
wire    [55:0] rx_preamble;                     //  Receive preamble
wire    rx_empty_st;                            //  RX FIFO empty (data+status)

//  FIFO to MAC (xlgmii_txclk)
//  -------------------------

wire    tx_stat_empty;                          //  Transmit Status FIFO Word Empty
wire    [2:0] tx_stat_mod;                      //  2:0 Last word modulo; valid with eop
wire    tx_stat_err;                            //  3: Error indication from FIFO; valid with eop
wire    tx_stat_crc;                            //  4: CRC append indication from FIFO; valid with eop
wire    [TSID_WIDTH-1:0] tx_stat_id;            //  Frame identifier
wire    tx_stat_ts_frm;                         //  Store timestamp command
wire    [55:0] tx_preamble_int;                 //  Receive preamble
wire    [63:0] tx_data_int;                     //  Transmit Data from FIFO
wire    tx_data_err_int;                        //  Data from FIFO memory is erroneous (ECC)
wire    tx_sop_int;                             //  Transmit Start of Packet
wire    tx_eop_int;                             //  Transmit End of Packet
wire    tx_sav_int;                             //  Transmit Data Section Available in FIFO
wire    tx_rden_int;                            //  Transmit Data FIFO Read enable (fifo to react with 1 cycle latency)
wire    tx_empty_int;                           //  Transmit Data FIFO Empty
`ifdef USER_PREAMBLE_ENA
wire    tx_rden_int_sop;                        //  Transmit reads first word from FIFO
`else
`ifdef MTIPMAC_1SIF
wire    tx_rden_int_sop;                        //  Transmit reads first word from FIFO
`endif
`endif

//  Controls
//  --------

wire    [ING_ADDR - 1:0] rx_section_empty;      //  Receive Section Empty - Pause Frame Generation Threshold
wire    [ING_ADDR - 1:0] rx_section_full;       //  Receive Section Full - FIFO Status
wire    [EG_ADDR - 1:0] tx_section_empty;       //  Transmit Section Empty - FIFO Status
wire    [EG_ADDR - 1:0] tx_section_full;        //  Transmit Section Full - MAC Tx Start
wire    rx_err_frm_disc;                        //  Discard erroneous frames if possible
wire    rx_short_disc;                          //  Discard Received short frames (within FIFO)
wire    [7:0] rx_credit_max;                    //  Credit counter init/max value
wire    rx_credit_reset;                        //  FIFO reset
wire    rx_credit_reset_done;                   //  FIFO reset completed; pulse
wire    [7:0] rx_credit;                        //  Current credit counter value
wire    sw_reset;                               //  Sw_reset bit (reg_clk); pulse
wire    tx_clk_ena;                             //  XLGMII Transmit Clock Enable to return to MAC
wire    rx_clk_ena;                             //  XLGMII Receive Clock Enable to return to MAC

//  Tx feedback
//  -----------

wire    tx_ts_val_int;                          //  tx_ts_xxx valid indication
wire    [TS_WIDTH-1:0] tx_ts_int;               //  Transmit timestamp
wire    [TSID_WIDTH-1:0] tx_ts_id_int;          //  Frame identifier
wire    tx_ts_frm_out_int;                      //  Transmit Timestamp Frame

//  FIFOs Reset
//  -----------

wire    tx_sw_reset;                            //  FIFO sync reset (ff_tx_clk)
wire    tx_sw_reset_done;                       //  FIFO reset completed, pulse (ff_tx_clk)
wire    [3 + RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_ff; //  Receive Status data
wire    rx_sw_reset;                            //  FIFO sync reset (ff_tx_clk)
wire    rx_sw_reset_done;                       //  FIFO reset completed, pulse (ff_tx_clk)

// clock domain sync
wire    [ING_ADDR - 1:0] rx_section_empty_s;    // sync'ed to rx_clk (fifo write)
wire    [ING_ADDR - 1:0] rx_section_full_s;     // sync'ed to ff_rx_clk (fifo read)
wire    [EG_ADDR - 1:0] tx_section_empty_s;     // sync'ed to ff_tx_clk (fifo write)
wire    [EG_ADDR - 1:0] tx_section_full_s;      // sync'ed to tx_clk (fifo read)

wire    xlgmii_txclk;                           //  XLGMII transmit clock
wire    xlgmii_rxclk;                           //  XLGMII receive clock

assign xlgmii_txclk = tx_clk;
assign xlgmii_rxclk = rx_clk;

`ifdef MTIPMAC_1SIF

assign os_tx_rden_int_sop = tx_rden_int_sop;
assign os_tx_sw_reset     = tx_sw_reset;

`endif


//  Timestamp Return Interface to Application clock domain
//  ------------------------------------------------------

tsm40_txret U_TSMTXRET (

          .reset_tx_clk(reset_txclk),
          .tx_clk(xlgmii_txclk),
          .tx_ts_val_int(tx_ts_val_int),
          .tx_ts_int(tx_ts_int),
          .tx_ts_id_int(tx_ts_id_int),
          .tx_ts_frm_out_int(tx_ts_frm_out_int),
          .reset_ff_tx_clk(reset_ff_tx_clk),
          .ff_tx_clk(ff_tx_clk),
          .tx_ts_val(tx_ts_val),
          .tx_ts(tx_ts),
          .tx_ts_id(tx_ts_id),
          .tx_ts_frm_out(tx_ts_frm_out));

//  MAC with Host Interface
//  -----------------------

top_40g_addon_xlgmii #(

        // use instance parameters instead package parameters
          .EG_FIFO(EG_FIFO)  , .EG_ADDR(EG_ADDR),       // TX FIFO size
          .ING_FIFO(ING_FIFO), .ING_ADDR(ING_ADDR),     // RX FIFO size
          .RX_STAT_DAT_WIDTH_64(RX_STAT_DAT_WIDTH_64)   // RX Frame Status
                                ) 
U_MACA (

          //  Host Interface
          .reset_reg_clk(reset_reg_clk),
          .reg_clk(reg_clk),
          .reg_rden(reg_rden),
          .reg_wren(reg_wren),
          .reg_addr(reg_addr),
          .reg_data_in(reg_data_in),
          .reg_data_out(reg_data_out),
          .reg_busy(reg_busy),
          .reg_ts_avail(reg_ts_avail),
          .reg_lowp(reg_lowp),
          .reg_lowp_ena(reg_lowp_ena),
          .lpi_txhold(lpi_txhold),
          //  MDIO Master
          .mdc(mdc),
          .mdio_in(mdio_in),
          .mdio_out(mdio_out),
          .mdio_oen(mdio_oen),
          //  control/status
          .loc_fault(loc_fault),
          .rem_fault(rem_fault),
          .li_fault(li_fault),
          .tx_loc_fault(tx_loc_fault),
          .tx_rem_fault(tx_rem_fault),
          .tx_li_fault(tx_li_fault),
          .phy_txena(phy_txena),
          .phy_los(phy_los),
          .loop_ena(loop_ena),
          .pfc_mode(pfc_mode),
          .pause_on(pause_on),
          .xoff_gen(xoff_gen),
          //  timestamping source (sync to line clocks)
          .rx_sfd_o(rx_sfd_o),
          .tx_sfd_o(tx_sfd_o),
          .frc_in_tx(frc_in_tx),
          .xgmii_rx_sop_shift(xgmii_rx_sop_shift),
          .xgmii_tx_sop_shift(xgmii_tx_sop_shift),
          //  Line Interface
          .reset_rxclk(reset_rxclk),
          .reset_txclk(reset_txclk),
          .tx_clk(xlgmii_txclk),
          .tx_clk_ena(tx_clk_ena),
          .rx_clk(xlgmii_rxclk),
          .rx_clk_ena(rx_clk_ena),
          .xlgmii_rxc(xlgmii_rxc),
          .xlgmii_rxd(xlgmii_rxd),
          .xlgmii_rxt0_next(xlgmii_rxt0_next),
          .xlgmii_txc(xlgmii_txc),
          .xlgmii_txd(xlgmii_txd),
          //  MAC to FIFO (xlgmii_rxclk)
          .reset_ff_rx_clk(reset_ff_rx_clk),
          .ff_rx_clk(ff_rx_clk),
          .rx_stat_wren(rx_stat_wren),
          .rx_stat_data(rx_stat_data),
          .rx_mod_int(rx_mod_int),
          .rx_data_int(rx_data_int),
          .rx_sop_int(rx_sop_int),
          .rx_eop_int(rx_eop_int),
          .rx_wren_int(rx_wren_int),
          .rx_dval_int(),
          .rx_a_full(rx_a_full),
          .rx_septy(rx_septy),
          .rx_preamble(rx_preamble),
          .rx_empty_st(rx_empty_st),
          //  FIFO to MAC (xlgmii_txclk)
          .reset_ff_tx_clk(reset_ff_tx_clk),
          .ff_tx_clk(ff_tx_clk),
          .tx_stat_empty(tx_stat_empty),
          .tx_stat_mod(tx_stat_mod),
          .tx_stat_err(tx_stat_err),
          .tx_stat_crc(tx_stat_crc),
          .tx_stat_id(tx_stat_id),
          .tx_stat_ts_frm(tx_stat_ts_frm),
          .tx_preamble_int(tx_preamble_int),
          .tx_data_err_int(tx_data_err_int),
          .tx_data_int(tx_data_int),
          .tx_sop_int(tx_sop_int),
          .tx_eop_int(tx_eop_int),
          .tx_sav_int(tx_sav_int),
          .tx_rden_int(tx_rden_int),
        `ifdef USER_PREAMBLE_ENA
          .tx_rden_int_sop(tx_rden_int_sop),
        `else
        `ifdef MTIPMAC_1SIF
          .tx_rden_int_sop(tx_rden_int_sop),
        `else
          .tx_rden_int_sop(),
        `endif
        `endif
        `ifdef MTIPMAC_1SIF
          .tx_rden_sop_pause(os_tx_rden_sop_pause),
        `else
          .tx_rden_sop_pause(),
        `endif
          .tx_empty(tx_empty_int),
          .tx_underflow(tx_underflow),
          //  transmit acknowledge Interface
          .tx_ts_val_int(tx_ts_val_int),
          .tx_ts_int(tx_ts_int),
          .tx_ts_id_int(tx_ts_id_int),
          .tx_ts_frm_out(tx_ts_frm_out_int),
          //  FIFO Threshold
          .rx_section_empty(rx_section_empty),  // reg_clk
          .rx_section_full(rx_section_full),    // reg_clk
          .tx_section_empty(tx_section_empty),  // reg_clk
          .tx_section_full(tx_section_full),    // reg_clk
          .rx_err_frm_disc(rx_err_frm_disc),    // reg_clk
          .rx_short_disc(rx_short_disc),        // reg_clk
          .rx_credit_max(rx_credit_max),
          .rx_credit_reset(rx_credit_reset),
          .rx_credit_reset_done(rx_credit_reset_done),
          .rx_credit(rx_credit),
          .sw_reset(sw_reset)
        `ifdef MTIPMAC_1SIF
          ,
          .os_tx_flush(os_tx_flush),
          .os_tx_err(os_tx_err),
          .os_enable(os_enable)
        `endif
        `ifdef MTIPM10_MAGIC_ENA
          ,
          .magic_ena(magic_ena),
          .magic_ind(magic_ind)
         `endif 
        `ifdef MTIPMAC_XSTAT
          ,
          .rsv_stat_val(rsv_stat_val),
          .rsv_stat(rsv_stat),
          .tsv_stat_val(tsv_stat_val),
          .tsv_stat(tsv_stat)
        `elsif MTIPSTAT_MEM_EXTERNAL
          ,
          .rstm_raddr(rstm_raddr),
          .rstm_rden (rstm_rden ),
          .rstm_rdata(rstm_rdata),
          .rstm_wren (rstm_wren ),
          .rstm_waddr(rstm_waddr),
          .rstm_wdata(rstm_wdata),
          .tstm_raddr(tstm_raddr),
          .tstm_rden (tstm_rden ),
          .tstm_rdata(tstm_rdata),
          .tstm_wren (tstm_wren ),
          .tstm_waddr(tstm_waddr),
          .tstm_wdata(tstm_wdata)
        `endif
          );

//  ------------------------------------------------
//  Implement the clock enable wirings and register.
//  ------------------------------------------------
//  Note: Clock enables not advance! No registers required.

assign tx_clk_ena = xlgmii_txclk_ena;
assign rx_clk_ena = xlgmii_rxclk_ena;

//  ------------------------------------------------
//  wire unused credit FIFO interface
//  ------------------------------------------------
assign rx_credit_reset_done = rx_credit_reset;
assign rx_credit = {8{1'b 0}};

//  ------------------------------------------------
//  Transmit FIFO
//  ------------------------------------------------

tx_ff64v2id #(

        .FF_WIDTH      (EG_WIDTH),      // Data Width (excluding SOP+EOP bits within memory)
        .DEPTH         (EG_FIFO),       // Data FIFO depth (max 512)
        .ADDR_WIDTH    (EG_ADDR),       // Data FIFO address bits
        .ST_DEPTH      (EG_ST_FIFO),    // Status FIFO depth
        .ST_ADDR_WIDTH (EG_ST_ADDR),    // Status FIFO address bits
        .MOD_WIDTH     (3),             // Modulo bits needed to support FF_WIDTH
        .AF_THRESHOLD  (7),             // Data FIFO almost full (minimum 7)
      `ifdef MTIPSDPM_GEN_READEN
        .AE_THRESHOLD  (4),             // Data FIFO almost empty (minimum 4)
      `else
        .AE_THRESHOLD  (3),             // Data FIFO almost empty (minimum 3)
      `endif
        .TSID_WIDTH    (TSID_WIDTH) )   // width for frame-id

        U_TXFF (

          .reset_txclk(reset_txclk),
          .reset_ff_tx_clk(reset_ff_tx_clk),
          .tx_sw_reset(tx_sw_reset),
          .tx_sw_reset_done(tx_sw_reset_done),
          .ff_tx_clk(ff_tx_clk),
          .ff_tx_data(ff_tx_data),
          .ff_tx_sop(ff_tx_sop),
          .ff_tx_eop(ff_tx_eop),
          .ff_tx_mod(ff_tx_mod),
          .ff_tx_err(ff_tx_err),
          .ff_tx_crc(ff_tx_crc),
          .ff_tx_wren(ff_tx_wren),
          .ff_tx_rdy(ff_tx_rdy),
          .ff_tx_septy(ff_tx_septy),
        `ifdef MTIP_PARITY_PROT
          .par_odd(ff_tx_par_odd),
          .tx_par_check_en(ff_tx_par_check_ena),
          .ff_tx_data_par(ff_tx_data_par),
          .ff_tx_ctrl_par(ff_tx_ctrl_par),
          .ff_tx_data_par_err(ff_tx_data_par_err),
          .ff_tx_ctrl_par_err(ff_tx_ctrl_par_err),
        `endif
          .ff_tx_id(ff_tx_id),
          .ff_tx_ts_frm(ff_tx_ts_frm),
          .ff_tx_ovr_err(tx_ovr_err),
        `ifdef USER_PREAMBLE_ENA
          .ff_tx_preamble(ff_tx_preamble),
        `endif
          .section(tx_section_full_s),  // sync'ed
          .sect_e(tx_section_empty_s),  // sync'ed
          .txclk(xlgmii_txclk),
          .txclk_ena(tx_clk_ena),          //  the true enable that goes to the MAC
          .tx_stat_empty(tx_stat_empty),
          .tx_stat_mod(tx_stat_mod),
          .tx_stat_err(tx_stat_err),
          .tx_stat_crc(tx_stat_crc),
          .tx_stat_id(tx_stat_id),
          .tx_stat_ts_frm(tx_stat_ts_frm),
          .tx_data_int(tx_data_int),
          .tx_data_err_int(tx_data_err_int),
          .tx_sav_int(tx_sav_int),
          .tx_empty(tx_empty_int),
          .tx_sop_int(tx_sop_int),
          .tx_eop_int(tx_eop_int),
         `ifdef USER_PREAMBLE_ENA
          .tx_preamble_int(tx_preamble_int),
          .tx_rden_int_sop(tx_rden_int_sop),
         `endif
          .tx_rden_int(tx_rden_int)
         `ifdef MTIPMAC_1SIF
          ,
          .os_dff_wren(os_dff_wren)
         `endif
         `ifdef FFMEM_EXTERNAL
          ,
          .txd_raddr(txd_raddr),
          .txd_rden(txd_rden),
          .txd_rdata(txd_rdata),
          .txd_recc(txd_recc),
          .txd_wren(txd_wren),
          .txd_waddr(txd_waddr),
          .txd_wdata(txd_wdata),
          .txs_raddr(txs_raddr),
          .txs_rden(txs_rden),
          .txs_rdata(txs_rdata),
          .txs_wren(txs_wren),
          .txs_waddr(txs_waddr),
          .txs_wdata(txs_wdata)
          `ifdef USER_PREAMBLE_ENA
          ,
          .txp_raddr(txp_raddr),
          .txp_rden (txp_rden),
          .txp_rdata(txp_rdata),
          .txp_wren (txp_wren),
          .txp_waddr(txp_waddr),
          .txp_wdata(txp_wdata)
          `endif
         `endif
          );

`ifndef USER_PREAMBLE_ENA
assign tx_preamble_int = 56'h d5555555555555;   //  byte0 is not configurable, hence missing here.
`endif


assign tx_empty = tx_empty_int & tx_stat_empty; // fifo completely empty

//  ------------------------------------------------
//  Receive FIFO
//  ------------------------------------------------

rx_ff64v2ts #(

        .FF_WIDTH       (ING_WIDTH),    // Data + Parity width (not for change)
        .DEPTH          (ING_FIFO),     // Data FIFO depth
        .ADDR_WIDTH     (ING_ADDR),     // Data FIFO address bits
        .ST_DEPTH       (ING_ST_FIFO),  // Status FIFO depth
        .ST_ADDR_WIDTH  (ING_ST_ADDR),  // Status FIFO address bits
        .TS_WIDTH       (TS_WIDTH),     // width of timestamp value
        .FF_OUT_REGISTERED(RXFF_OUT_REGISTERED),           // extra output registers at application interface
        .RX_STAT_DAT_WIDTH_64(RX_STAT_DAT_WIDTH_64)

) U_RXFF (

          .reset_rxclk(reset_rxclk),
          .reset_ff_rx_clk(reset_ff_rx_clk),
          .rx_err_frm_disc(rx_err_frm_disc),
          .rx_short_disc(rx_short_disc),
        `ifdef MTIP_PARITY_PROT
          .par_odd(ff_rx_par_odd),
        `endif
          .rx_sw_reset(rx_sw_reset),
          .rx_sw_reset_done(rx_sw_reset_done),
          .rxclk(xlgmii_rxclk),
          .rx_stat_data(rx_stat_data_ff),
          .rx_stat_wren(rx_stat_wren),
          .rx_data_int(rx_data_int),
          .rx_a_full(rx_a_full),
          .rx_septy(rx_septy),
          .rx_sop_int(rx_sop_int),
          .rx_eop_int(rx_eop_int),
          .rx_wren_int(rx_wren_int),
          .rx_ts_int(frc_in_rx),
        `ifdef USER_PREAMBLE_ENA
          .rx_preamble_int(rx_preamble),
        `endif
          .section(rx_section_full_s),  // sync'ed
          .sect_e(rx_section_empty_s),  // sync'ed
          .ff_rx_clk(ff_rx_clk),
          .ff_rx_data(ff_rx_data),
          .ff_rx_sop(ff_rx_sop),
          .ff_rx_eop(ff_rx_eop),
          .ff_rx_mod(ff_rx_mod),
          .ff_rx_err(ff_rx_err),
          .ff_rx_err_stat(ff_rx_err_stat),
        `ifdef MTIP_PARITY_PROT
          .ff_rx_data_par(ff_rx_data_par),
          .ff_rx_ctrl_par(ff_rx_ctrl_par),
          .ff_rx_stat_par(ff_rx_stat_par),
        `endif
          .ff_rx_rdy(ff_rx_rdy),
          .ff_rx_dval(ff_rx_dval),
          .ff_rx_dsav(ff_rx_dsav),
          .ff_rx_ts(ff_rx_ts),
        `ifdef USER_PREAMBLE_ENA
          .ff_rx_preamble(ff_rx_preamble),
        `endif
          .ff_rx_empty(rx_empty_st)    // ff_rx_empty)

        `ifdef FFMEM_EXTERNAL
          ,
        .rxd_raddr(rxd_raddr),
        .rxd_rden (rxd_rden),
        .rxd_rdata(rxd_rdata),
        .rxd_recc (rxd_recc),
        .rxd_wren (rxd_wren),
        .rxd_waddr(rxd_waddr),
        .rxd_wdata(rxd_wdata),
        .rxs_raddr(rxs_raddr),
        .rxs_rden (rxs_rden),
        .rxs_rdata(rxs_rdata),
        .rxs_wren (rxs_wren),
        .rxs_waddr(rxs_waddr),
        .rxs_wdata(rxs_wdata),
        .rxp_raddr(rxp_raddr),
        .rxp_rden (rxp_rden),
        .rxp_rdata(rxp_rdata),
        .rxp_wren (rxp_wren),
        .rxp_waddr(rxp_waddr),
        .rxp_wdata(rxp_wdata)
        `endif

          );

assign ff_rx_empty     = rx_empty_st;
assign rx_stat_data_ff = {rx_mod_int, rx_stat_data};


// --------------------------------
// clock domain crossings for FIFOs
// --------------------------------

//  FIFO Resets.

redge_ckxing U_RSTTX (

          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(sw_reset),
          //  Output clock domain
          .reset_clk_o(reset_ff_tx_clk),
          .clk_o(ff_tx_clk),
          .sig_o(tx_sw_reset));

redge_ckxing U_RSTRX (

          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(sw_reset),
          //  Output clock domain
          .reset_clk_o(reset_ff_rx_clk),
          .clk_o(ff_rx_clk),
          .sig_o(rx_sw_reset));


// FIFO configuration signals

mtip_xsync #(ING_ADDR) U_RFFW_SY (
          .data_in(rx_section_empty), .reset(reset_rxclk),      .clk(xlgmii_rxclk),.data_s(rx_section_empty_s));   // fifo write

mtip_xsync #(ING_ADDR) U_RFFR_SY (
          .data_in(rx_section_full),  .reset(reset_ff_rx_clk),  .clk(ff_rx_clk),.data_s(rx_section_full_s));    // fifo read

mtip_xsync #(EG_ADDR) U_TFFW_SY (
          .data_in(tx_section_empty), .reset(reset_ff_tx_clk),  .clk(ff_tx_clk),.data_s(tx_section_empty_s));   // fifo write

mtip_xsync #(EG_ADDR) U_TFFR_SY (
          .data_in(tx_section_full),  .reset(reset_txclk),      .clk(xlgmii_txclk),.data_s(tx_section_full_s));    // fifo read


endmodule // module top_xlgmac_64
